/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Tencent is pleased to support the open source community by making behaviac available.
//
// Copyright (C) 2015 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at http://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed under the License is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and limitations under the License.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef _CORE_VALUETOSTRING_H_
#define _CORE_VALUETOSTRING_H_

#include "behaviac/base/base.h"
#include "behaviac/base/core/container/string_t.h"
#include "behaviac/base/core/container/vector_t.h"
#include "behaviac/base/core/container/list_t.h"
#include "behaviac/base/core/container/map_t.h"
#include "behaviac/base/core/container/set_t.h"

#include "behaviac/base/meta/meta.h"
#include "behaviac/base/meta/isenum.h"

namespace behaviac
{
    namespace Meta
    {
        template<typename Type>
        struct HasToString
        {
        private:

			template<typename U, behaviac::string (U::*)() const> struct SFINAE {};

            template< typename U >
            static Yes Tester(SFINAE<U, &U::ToString>*);

            template<typename U>
            static No Tester(...);

        public:

            enum
            {
                Result = sizeof(Tester<Type>(0)) == sizeof(Yes)
            };
        };
    }
}

template<typename T>
behaviac::string EnumValueToString(const T& v);

namespace behaviac
{
namespace StringUtils
{
	template<typename T>
	behaviac::string ToString(const T& val);

	namespace Private
	{
		template<typename T>
		inline behaviac::string ToString(const T& val)
		{
			BEHAVIAC_UNUSED_VAR(val);

			return "";
		}

		// Basic types
		inline behaviac::string ToString(bool val)
		{
			return val ? "true" : "false";
		}
		inline behaviac::string ToString(char val)
		{
			char str[2];
			string_sprintf(str, "%c", val);
			return str;
		}
		inline behaviac::string ToString(signed char val)
		{
			char str[5];
			string_sprintf(str, "%i", val);
			return str;
		}
		inline behaviac::string ToString(unsigned char val)
		{
			char str[5];
			string_sprintf(str, "%u", val);
			return str;
		}
		inline behaviac::string ToString(signed short val)
		{
			char str[7];
			string_sprintf(str, "%i", val);
			return str;
		}
		inline behaviac::string ToString(unsigned short val)
		{
			char str[7];
			string_sprintf(str, "%u", val);
			return str;
		}
		inline behaviac::string ToString(signed int val)
		{
			char str[12];
			string_sprintf(str, "%i", val);
			return str;
		}
		inline behaviac::string ToString(unsigned int val)
		{
			char str[12];
			string_sprintf(str, "%u", val);
			return str;
		}
	
		inline behaviac::string ToString(signed long val)
		{
			char str[12];
			string_sprintf(str, "%li", val);
			return str;
		}
		inline behaviac::string ToString(unsigned long val)
		{
			char str[12];
			string_sprintf(str, "%lu", val);
			return str;
		}
#if !BEHAVIAC_COMPILER_GCC_LINUX
		inline behaviac::string ToString(int64_t val)
		{
			char str[23];
			string_sprintf(str, "%lli", val);
			return str;
		}
		inline behaviac::string ToString(uint64_t val)
		{
			char str[23];
			string_sprintf(str, "%llu", val);
			return str;
		}
#else
		inline behaviac::string ToString(long long val)
		{
			char str[23];
			string_sprintf(str, "%lli", val);
			return str;
		}
		inline behaviac::string ToString(unsigned long long val)
		{
			char str[23];
			string_sprintf(str, "%llu", val);
			return str;
		}
#endif
		inline behaviac::string ToString(float val)
		{
			char str[32];
			string_sprintf(str, "%f", val);
			return str;
		}
		inline behaviac::string ToString(double val)
		{
			char str[32];
			string_sprintf(str, "%g", val);
			return str;
		}
		inline behaviac::string ToString(void* val)
		{
			char str[32];
			string_sprintf(str, "%p", val);
			return str;
		}

		inline behaviac::string ToString(const char* val)
		{
			behaviac::string ret(val);
			return ret;
		}

		inline behaviac::string ToString(const std::string& val)
		{
			return behaviac::string(val.c_str());
		}

		inline behaviac::string ToString(const std::wstring& val)
		{
			behaviac::wstring t(val.c_str());
			behaviac::string r = behaviac::StringUtils::Wide2Char(t);

			return behaviac::string(r.c_str());
		}

		inline behaviac::string ToString(const behaviac::string& val)
		{
			return val;
		}

		inline behaviac::string ToString(const behaviac::wstring& val)
		{
			return behaviac::StringUtils::Wide2Char(val);
		}

		inline behaviac::string ToString(const CStringID& val)
		{
			return val.LogStr();
		}

		inline behaviac::string ToString(const CPathID& val)
		{
			return val.LogStr();
		}


		// Container types
		template <typename T> behaviac::string ContainerToString(const T& contVal)
		{
			behaviac::string str;
			char count[64];
			string_sprintf(count, "%d:", (int)contVal.size());
			str = count;
			typename T::const_iterator iter = contVal.begin();
			typename T::const_iterator iterEnd = contVal.end();

			while (iter != iterEnd)
			{
				str += behaviac::StringUtils::ToString(*iter);
				str += "|";
				++iter;
			}

			return str;
		}
		template <typename T> behaviac::string ToString(const behaviac::vector<T>& contVal)
		{
			return ContainerToString(contVal);
		}
		template <typename T> behaviac::string ToString(const behaviac::list<T>& contVal)
		{
			return ContainerToString(contVal);
		}
		template <typename T> behaviac::string ToString(const behaviac::set_t<T>& contVal)
		{
			return ContainerToString(contVal);
		}
	}//namespace Private

	namespace Detail
	{
		template<typename T, bool bIsEnum>
		struct ToStringEnumHanler
		{
			static behaviac::string ToString(const T& v)
			{
				behaviac::string valueStr = Private::ToString(v);

				return valueStr;
			}
		};

		template<typename T>
		struct ToStringEnumHanler<T, true>
		{
			static behaviac::string ToString(const T& v)
			{
				return EnumValueToString(v);
			}
		};


		template<typename T, bool bHasToString>
		struct ToStringStructHanler
		{
			static behaviac::string ToString(const T& val)
			{
				return ToStringEnumHanler<T, behaviac::Meta::IsEnum<T>::Result>::ToString(val);
			}
		};

		template<typename T>
		struct ToStringStructHanler<T, true>
		{
			static behaviac::string ToString(const T& val)
			{
				return val.ToString();
			}
		};
	}//namespace Detail

	template<typename T>
	inline behaviac::string ToString(const T& val)
	{
		return Detail::ToStringStructHanler<T, behaviac::Meta::HasToString<T>::Result>::ToString(val);
	}
}
}


#endif // #ifndef _CORE_VALUETOSTRING_H_
